package org.cnc.core;

import java.awt.event.KeyEvent;
import java.net.InetAddress;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.cnc.core.DetailModel.ModelState;
import org.cnc.core.MachineControl.Command;
import org.cnc.core.MachineControl.MachineMode;
import org.cnc.gui.SettingsPanel;
import org.cnc.gui.StatusPanel;
import org.cnc.machine.CutterPosition;
import org.cnc.rmi.interfaces.MachineControlCallbackInterface;
import org.cnc.rmi.interfaces.MachineControlInterface;
import org.cnc.rmi.interfaces.ModelDrawerInterface;
import org.cnc.rmi.interfaces.RmiServer;

public class CncCore implements ChangeListener {

	private ModelBuilder modelBuilder = new ModelBuilder();
	private ModelDrawerInterface modelDrawer;
	private MachineControlInterface machineControl;
	private MachineListener machineListener;
	private DetailModel model;
	private StatusPanel status;
	private Server server;
	
	@SuppressWarnings("serial")
	class Server extends RmiServer
	implements MachineControlCallbackInterface
	{

		public Server(String name, int port) throws RemoteException {
			super(name, port);
			// TODO Auto-generated constructor stub
		}

		@Override
		public void cutterChanged(CutterPosition pos) throws RemoteException {
			
			stateChanged( new ChangeEvent(pos) );
		}
		
	}
	
	public DetailModel getModel() {
		return model;
	}
	
	public CutterPosition getCutterPos()
	{
		CutterPosition pos;
		
		try
		{
			pos = machineControl.getCutterPosition();
		}
		catch ( Exception e )
		{
			e.printStackTrace();
			pos = null;
		}
		
		return pos;
	}
	
	@Override
	public void stateChanged(ChangeEvent e) {

		if (e.getSource() instanceof SettingsPanel)
		{
			final SettingsPanel s = (SettingsPanel)e.getSource();		
			model = modelBuilder.buildModelByXYZ(s.getXMax(), s.getYMax(), s.getZMax());

	        new Thread(
	                new Runnable() {
	                    public void run() {
					                       
							try {
								
								if ( machineControl == null )
									machineReload();
								
								if ( machineControl != null )
								{
									machineControl.generateCommands(model);
									machineControl.setDelayTime( s.getTZad() );
								}
							}
							catch ( Exception ex )
							{
								ex.printStackTrace();
							}
	        }}).start();
			
			redrawGraphics();
		}
		else if (e.getSource() instanceof CutterPosition)
		{
			try
			{
				
				CutterPosition pos = (CutterPosition)e.getSource();
				
				if ( model.detailModel[pos.x()][pos.y()][pos.z()] != ModelState.EMPTY )
					model.detailModel[pos.x()][pos.y()][pos.z()] = ModelState.CUTTED;
				
				
				modelDrawer.update(model, pos.x(), model.getModelSize() - pos.y(), pos.z());
				
				
			}
			catch (RemoteException e1)
			{
				e1.printStackTrace();
				System.out.println("\n\n" + modelDrawer.toString());
			}
		}
		else if ( e.getSource() instanceof StatusPanel )
		{
			startMachine();
		}
	}

	public void connectModelDrawer(ModelDrawerInterface drawer)
	{
		this.modelDrawer = drawer;
		redrawGraphics();
	};
	
	public void connectStatusPanel ( StatusPanel s )
	{
		this.status = s;
	}
	
	private void machineReload()
	{
		try {
			server = new Server("core", 5500);
			
			String machineAddress = (InetAddress.getLocalHost().getHostAddress()).toString();
			String machinePort = "3100";
			
			Registry machineRegistry = LocateRegistry.getRegistry(
					machineAddress,
						(new Integer(machinePort)).intValue());
			
			machineControl = (MachineControlInterface)(machineRegistry.lookup("machine"));
			
			machineListener = new MachineListener( machineControl );
			machineListener.addChangeListener(this);
			
			machineControl.generateCommands(model);	
		}
		catch ( Exception e )
		{
			machineControl = null;
		}
	}
	public CncCore ()
	{
		model = modelBuilder.buildModelByXYZ(1, 1, 1);

		machineReload();
	}
	
	public void startMachine()
	{
		try {
			if ( machineControl == null )
				machineReload();
			
			if ( machineControl != null )
			{
				machineControl.startMachine();
				machineListener.start(); 
			}
		}
		catch ( Exception e )
		{
			e.printStackTrace();
		}
		
	}
	
	public void stopMachine()
	{
		try {
			if ( machineControl == null )
				machineReload();
			
			if ( machineControl != null )
			{
				machineControl.stopMachine();
				machineListener.suspend();
			}
		}
		catch ( Exception e )
		{
			e.printStackTrace();
		}
	}
	
	protected void redrawGraphics() {
		
		try {
			modelDrawer.update( model, 0, 0, 0 );
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	public void pressKey( final int keyCode) {

        new Thread(
                new Runnable() {
                    public void run() {
				                       
						try {
							
							if ( machineControl == null )
								machineReload();
							
							if ( machineControl != null )
							{
								if ( keyCode == KeyEvent.VK_H )
								{
									machineControl.setMode( MachineMode.MANUAL.toString() );
								}
								else if ( keyCode == KeyEvent.VK_I )
								{
									machineControl.makeStep();
								}
								else if ( keyCode == KeyEvent.VK_F )
								{
									machineControl.setMode( MachineMode.AUTOMATIC.toString() );
								}
								else if ( keyCode == KeyEvent.VK_NUMPAD6 )
								{
									machineControl.makeStep( Command.RIGHT.toString() );
								}
								else if ( keyCode == KeyEvent.VK_NUMPAD4 )
								{
									machineControl.makeStep( Command.LEFT.toString() );
								}
								else if ( keyCode == KeyEvent.VK_NUMPAD8 )
								{
									machineControl.makeStep( Command.UP.toString() );
								}
								else if ( keyCode == KeyEvent.VK_NUMPAD2 )
								{
									machineControl.makeStep( Command.DOWN.toString() );
								}
								else if ( keyCode == KeyEvent.VK_NUMPAD5 )
								{
									machineControl.makeStep( Command.STOP.toString() );
								}
								else if ( keyCode == KeyEvent.VK_NUMPAD1 )
								{
									machineControl.makeStep( Command.BACK.toString() );
								}
								else if ( keyCode == KeyEvent.VK_NUMPAD7 )
								{
									machineControl.makeStep( Command.FORWARD.toString() );
								}
							}
						}
						catch ( Exception e)
						{
							e.printStackTrace();
						}
		
            }
        }).start();
	}

}